PlayerType = {
    COMPUTER:"COMPUTER",
    HUMAN:"HUMAN"
};

GameModeSelection = {
    PLAYERvsPLAYER:"PLAYERvsPLAYER",
    MultiPLAYER:"MultiPLAYER"
};

GameModeSelectionKEYS = {
    NUM1:"49",
    NUM2:"50"
};

KeyBoardType = {
    WASD:"WASD",
    ARROWS:"ARROWS"
};
ArrowKeysEnums = {
    LEFT:37,
    UP:38,
    RIGHT:39,
    DOWN:40,
    PLANT:76 // l
};
WASDEnums = {
    LEFT:65,
    UP:87,
    RIGHT:68,
    DOWN:83,
    PLANT:71 // g
};

ControlKeysEnums = {
    CTRL:17,
    ESC:27
};

function loadImage(name) {
    OurGame.images[name] = new Image();
    OurGame.images[name].onload = function () {
        resourceLoaded();
    };
    OurGame.images[name].src = "img/" + name + ".png";
}

/**
 * .wav files only
 *
 * @param name without extension
 */
function loadSound(name) {
    var audio = new Audio();
    audio.addEventListener('canplaythrough', resourceLoaded, false);
    audio.src = "sound/" + name + ".wav";
    OurGame.sounds[name] = audio;
}

function resourceLoaded() {
    OurGame.numResourcesLoaded += 1;
    if (OurGame.numResourcesLoaded == OurGame.totalResources) {
        OurGame.contentLoaded = true;
    }
}

function getMouse(e) {
    var element = OurGame.canvas, offsetX = 0, offsetY = 0, mx, my;

    // Compute the total offset
    if (element.offsetParent !== undefined) {
        do {
            offsetX += element.offsetLeft;
            offsetY += element.offsetTop;
        } while ((element = element.offsetParent));
    }

    mx = e.pageX - offsetX;
    my = e.pageY - offsetY;

    // We return a simple javascript object (a hash) with x and y defined
    return {x:mx, y:my};
}
function drawGridObject(spriteSheet, sx, sy, x, y) {
    try {
        OurGame.ctx.drawImage(spriteSheet, sx * OurGame.maxGrid, sy * OurGame.maxGrid, OurGame.maxGrid, OurGame.maxGrid, x, y, OurGame.maxGrid, OurGame.maxGrid);
    } catch (e) {
        stickyError('drawGridObject error occurred!', 'ERROR: ' + e);
    }
}

/**
 * checks if place is free of bombs and walls and is in canvas area
 *
 * @param x
 * @param y
 * @returns {Boolean}
 */
function isPlaceFree(x, y) {
    try {
        if (x < 0 || x > OurGame.grid * 18 || y < 0 || y > OurGame.grid * 15) {
            return false;
        }
        var t = level.map[x][y];
        if (t.length > 0) {
            switch (t.charAt(0)) {
                case 'w':
                    return false;
                case 'e':
                    return false;
                case 'h':
                    return false;
            }
        }
    } catch (err) {
        return false;
    }

    return getItemIndexByPos(OurGame.bombs, x, y) <= -1;

}

var uniqueID = (function () {
    var id = 0; // This is the private persistent value
    // The outer function returns a nested function that has access
    // to the persistent value.  It is this nested function we're storing
    // in the variable uniqueID above.
    return function () {
        return id++;
    };  // Return and increment
})(); // Invoke the outer function after defining it.

var bombUniqueID = (function () {
    var id = 0;
    return function () {
        return id++;
    };  // Return and increment
})(); // Invoke the outer function after defining it.

/**
 * @param items array of objects which as getPosX and getPosY getters
 * @param x
 * @param y
 * @returns object or -1 if not found
 */
function getItemByPos(items, x, y) {
    var index = getItemIndexByPos(items, x, y);
    if (index != -1) {
        return items[index];
    }
    return index;
}

/**
 * @param items array of objects which as getPosX and getPosY getters
 * @param x
 * @param y
 * @returns {Number} if not found -1
 */
function getItemIndexByPos(items, x, y) {
    for (var i = 0; i < items.length; i++) {
        if (items[i]) {
            if (items[i].getPosX() == x && items[i].getPosY() == y) {
                return i;
            }
        }
    }
    return -1;
}

function mouseDownOnButtons(e) {
    var buttons = OurGame.buttons;
    var mouse = getMouse(e);
    var mx = mouse.x;
    var my = mouse.y;
    var l = buttons.length;
    for (var i = l - 1; i >= 0; i--) {
        if (buttons[i].isWithinBounds(mx, my)) {
            buttons[i].onClick();
        }
    }
}

function mouseMoveOnButtons(e) {
    var gameModeList = OurGame.buttons;
    var mouse = getMouse(e);
    var mx = mouse.x;
    var my = mouse.y;
    var l = gameModeList.length;
    for (var i = l - 1; i >= 0; i--) {
        if (gameModeList[i].isWithinBounds(mx, my)) {
            gameModeList[i].setBorder(true);
        } else {
            gameModeList[i].setBorder(false);
        }
    }

}

function getElementIndexByTypeAndID(id, type) {
    switch (type) {
        case "p":
            for (var i = 0; i < OurGame.players.length; i++) {
                if (OurGame.players[i]) {

                    if (OurGame.players[i].id === id) {
                        return i;
                    }
                }
            }
            break;
        case "b":
            for (var j = 0; j < OurGame.bombs.length; j++) {
                if (OurGame.bombs[j]) {
                    if (OurGame.bombs[j].id === id) {
                        return j;
                    }
                }
            }
            break;
    }
    return null;
}
function removeObjectFromMatrixElementWithIndex(x, y, index, type) {
    try {
        var matrixObjects = level.map[x][y].split("/");
        for (var i = 0; i < matrixObjects.length; i++) {
            if (matrixObjects[i].slice(1) === index && type === matrixObjects[i].charAt(0)) {
                matrixObjects[i] = "";
            }
        }
        return matrixObjects;
    } catch(e) {
        log('ERROR in removeObjectFromMatrixElementWithIndex: ' + e);
    }
}
function removeObjectFromMatrixElement(x, y, type) {
    try {
        var matrixObjects = level.map[x][y].split("/");
        for (var i = 0; i < matrixObjects.length; i++) {
            if (type === matrixObjects[i].charAt(0)) {
                matrixObjects[i] = "";
            }
        }
        return matrixObjects;
    } catch (e) {
        log('ERROR in removeObjectFromMatrixElement: ' + e);
    }
}

function createUpdatedMatrixElement(matrixObjects) {
    var matrixElementNew = "";
    for (var j = 0; j < matrixObjects.length; j++) {
        if (matrixObjects[j] !== "") {
            if (matrixElementNew.length !== 0) {
                matrixElementNew += ("/" + matrixObjects[j]);
            } else {
                matrixElementNew = matrixObjects[j];
            }
        }
    }
    return matrixElementNew;
}
function removeMatrixObject(old_x, old_y, id, type, lopp) {
    if (lopp) {
        log("id: " + id);
    }
    var index = getElementIndexByTypeAndID(id, type);
    if (lopp) {
        log("index: " + index);
    }
    index = index.toString();
    var x = Math.floor(old_x / OurGame.grid);
    var y = Math.floor(old_y / OurGame.grid);
    if (lopp) {
        log("x: " + x);
    }
    var matrixObjects = removeObjectFromMatrixElementWithIndex(x, y, index, type);

    var matrixElementNew = createUpdatedMatrixElement(matrixObjects);
    if (matrixElementNew === "") {
        level.map[x][y] = "f0";
    } else {
        level.map[x][y] = matrixElementNew;
    }
    if (lopp) {
        log(level.map[x][y]);
    }

}

function getURLParameter(name) {
    name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
    var regexS = "[\\?&]" + name + "=([^&#]*)";
    var regex = new RegExp(regexS);
    var results = regex.exec(location.search);
    if (results == null)
        return undefined;
    return results[1];
}

function checkForAndAddUpgrade(matrixElement, i, x, y) {
    if (matrixElement.charAt(0) === "u" && OurGame.players[i]) {
        if (OurGame.players[i].getID() == OurGame.UID && OurGame.isMultiplayer || !OurGame.isMultiplayer) {
            var charAtOne = matrixElement.charAt(1);
            if (OurGame.players[i].addUpgrade(charAtOne)) {
                matrixElement = f0;
                if (OurGame.players[i].getID() == OurGame.UID && OurGame.isMultiplayer) {
                    takeUpgrade(OurGame.players[i], x, y, charAtOne);
                }
            }
        }
    }
    return matrixElement;
}

function isNotAlreadyInElement(matrixElement, index, type) {
    var matrixObjects = matrixElement.split("/");
    for (var i = 0; i < matrixObjects.length; i++) {
        if (matrixObjects[i].slice(1) === index && matrixObjects[i].charAt(0) === type) {
            return false;
        }
    }
    return true;
}

function addGeneratedUpgrades(upgrades) {
    for (var i = 0; i < upgrades.length; i++) {
        level.map[upgrades[i].x][upgrades[i].y] = level.map[upgrades[i].x][upgrades[i].y] + "/" + blocks.upgradable[upgrades[i].nr];
    }
}

function generateUpgrades() {
    var generatedUpgrades = [];
    for (var i = 0; i < level.map.length; i++) {
        for (var j = 0; j < level.map[0].length; j++) {
            if (level.map[i][j] === e3) {
                var randomUpgrade = Math.floor(Math.random() * blocks.upgradable.length);
                generatedUpgrades.push({"x":i, "y":j, "nr":randomUpgrade});
            }
        }
    }
    return generatedUpgrades;
}

function isLocalhost() {
    return window.location.toString().indexOf('localhost') >= 0 || window.location.toString().indexOf('127.0.0.1') >= 0;
}

function removeNULLfromarray(array) {
    var newArray = [];
    for (var i = 0; i < array.length; i++) {
        if (array[i] !== null) {
            newArray.push(array[i]);
        }
    }
    return newArray;
}

function makeUrl(deepLink) {
    var curUrl = window.location.pathname.split('/?');
    var params = curUrl[1];
    if (params === undefined) {
        params = ''
    } else {
        params += '/';
    }
    return deepLink + params;
}

function to_utf8(s) {
    var s2 =s;
    var lastIndex = 0;
    var firstPass = true;
   for (var i = 0; i < s.length; i++){
       if (s2[i] === "\\" && firstPass){
           firstPass = false;
           lastIndex = i;
       }else if(s2[i] === "\\"){
           var code = s2.slice(lastIndex+2, i);
           var uni = '"\\u' + code + '"';
           var utf8 = eval(uni);
           s2 = s2.slice(0, lastIndex) + utf8 + s2.slice(i);
           lastIndex = i-5;
       }else if(!firstPass && i == (s.length-1)){
           var code = s2.slice(lastIndex+2, lastIndex+6);
           var uni = '"\\u' + code + '"';
           var utf8 = eval(uni);
           s2 = s2.slice(0, lastIndex) + utf8+ s2.slice(lastIndex+6);
       }

   }
    return s2;
}